1 Packages, Data and Custom Functions

Custom Functions: This code chunk contains custom fucntions that I use to help automate or make tasks easier.

LoadPackages <- function(packages) {
  # Load or install packages if they aren't already loaded.
  #
  # Args:
  #   packages: a vector of package names
  #
  for (package in packages) {
    if (!require(package, character.only=T, quietly=T)) {
      if (!package %in% installed.packages()) install.packages(package)
      library(package, character.only=T)
    }
  }
}
ColNa <- function(df) {
  # Return a vector of column names that have NA values
  #
  # Args:
  # df: data frame 
  #
  # Returns:
  #  vector of column names that have NAs 
  df <- tbl_df(df)
  v <- c()
  j <- 1
  for(i in 1:ncol(df)) {
    x <- df[ ,i]
    xRmvNA <- x[!is.na(x),]
    lenx <- nrow(x)
    lenxRmvNA <- nrow(xRmvNA)
    if(lenx != lenxRmvNA ) {
      v[j] <- colnames(df[ ,i])
      j <- j+1
    }
  }
  return(v)
}

Load Packages: Packages contain functions that others write that help with doing stuff

# I use my custom function LoadPackages to load or install packages
LoadPackages(c("dplyr", "haven", "stringr", "tidyr", "ggplot2"))

Read in data

data_path <- 'E:/Tommy/Original_Data/Data'
# The list.files function gets the file names in a specified directory
# file_names contains the file names of all the data sets
file_names <- list.files(path = data_path, recursive = TRUE)
# Initialize a vector to hold data frame names
df_names <- c()
i <- 1
# This loop goes through the file names and reads it into R
for(name in file_names) {
  # create variable name for df
  df_name <- str_replace_all(name, " |_with_ann2|.sas7bdat|/acs_16_5yr|_records", "")
  # read in data
  df <- read_sas(paste0(data_path, "/", name))
  # attach df to variable name
  assign(df_name, df) 
  print(paste0("done with: ", df_name, " ", i,"/",length(file_names)))
  i <- i+1
  # add the current iteration of the data frame name to the df_names vector
  df_names <- c(df_names, df_name)
}

2 Data Descritpions

DF names for the data that was read in.
- There are 27 sets of demographics data. 9 simliar sets for each state (MA NC OR)
- The data sets that start with copy are exact copies of other datasets and can be ignored
- The medication_details dataset has some info about the drug (ex. price, manufacture etc.)
- rx_nqty: quantity of NEW opiod pills for each month by zip code
- rx_nrx: number of NEW opiod prescriptions for each month by zip code
- rx_tqty: quantity of TOTAL opiod pills for each month by zip code
- rx_trx: number of TOTAL opiod prescriptions for each month by zip code

df_names %>% as.data.frame()

The medication_details dataset has some info about the drug (ex. price, manufacture etc.)

medication_details

rx_nqty: quantity of NEW opiod pills for each month by zip code

rx_nqty

rx_nrx: number of NEW opiod prescriptions for each month by zip code

rx_nrx

rx_tqty: quantity of TOTAL opiod pills for each month by zip code

rx_tqty

rx_trx: number of TOTAL opiod prescriptions for each month by zip code

rx_trx

MA_s0101: Age and sex demographics data for each zip code in massachusetts
Column HC01_EST_VC01: is total population for the respective zip code
Column HC02_EST_VC01: total male population for the respective zip code
Column HC03_EST_VC01: total femal population for respective zip code
- You can view the data dictionary to find out what the other columns mean
- The other demographics data sets likely have a very simialr format

MA_s0101

Check that the files named with copy really just are duplicates

rx_nqty %>%
  all_equal(Copyofrx_nqty)
Copyofrx_nrx %>%
  all_equal(rx_nrx)
Copyofrx_tqty %>%
  all_equal(Copyofrx_tqty)
Copyofrx_trx %>%
  all_equal(rx_trx)

3 Total Rx By State

Prepare data to see total rx by state for each month

rx_trx_t <- rx_trx %>% select(ST, starts_with("TRx"))
rx_trx_t <- rx_trx %>%
  select(ST, starts_with("TRx")) %>%
  group_by(ST) %>% 
  summarise_all(funs(sum(.))) %>% 
  ungroup() %>% 
  gather(key = "date", value = TRx, -ST) %>%
  mutate(date = str_replace_all(date, "TRx_", "")) %>% 
  mutate(date = as.Date(date, '%m%d%Y')) %>%
  mutate(pop = ifelse(ST == 'MA', 6.86, 
                      ifelse(ST == "OR", 4.143, 10.27)),
         rx_pop_ratio = TRx / pop)
# prepare data to see difference between total rx for NC and MA
MA_rx_pop <- rx_trx_t %>% 
  filter(ST == "MA") %>% 
  mutate(MA_rx = rx_pop_ratio) %>% 
  select(MA_rx)
OR_rx_pop <- rx_trx_t %>% 
  filter(ST == "OR") %>% 
  mutate(OR_rx = rx_pop_ratio) %>% 
  select(OR_rx)
NC_rx_pop <- rx_trx_t %>% 
  filter(ST == "NC") %>% 
  mutate(NC_rx = rx_pop_ratio) %>% 
  select(NC_rx)
diff_df <- bind_cols(rx_trx_t %>% distinct(date), MA_rx_pop, OR_rx_pop, NC_rx_pop) %>%
  mutate(NC_MA_diff = NC_rx - MA_rx)

Line plot of total rx by state for each month

ggplot(data = rx_trx_t, aes(x = date, y = TRx, color = ST)) +
  geom_line() +
  ggtitle("Total Rx")

ggplot(data = rx_trx_t, aes(x = date, y = rx_pop_ratio, color = ST)) +
  geom_line() +
  ggtitle("Total Rx per Million Residents")

ggplot(data = diff_df, aes(x = date, y = NC_MA_diff)) +
  geom_line() +
  ggtitle("Diff Total Rx per Million Residents Between NC and MA")

Bar Chart of Total Scripts for each State

4 MISC (scratch / junk).

foo <- rx_trx %>% group_by(city, ST, Zip) %>% summarise(sum(TRx_08312017))
# cast to numeric data type
MA_s0101_d <- MA_s0101 %>% mutate_all(funs(as.double(.)))
NAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercionNAs introduced by coercion
# get col names that have NA values
na <- ColNa(MA_s0101_d)
# get all col names
all <- names(MA_s0101)
# this  is column names that don't have any NA values
setdiff(all,na)
[1] "Zip"           "HC01_EST_VC01" "HC02_EST_VC01" "HC03_EST_VC01"

Write datesets out as csv files

for (name in df_names) {
  write.csv(get(name), paste0('E:/Tommy/scratch/csv/',name,".csv"))
}
LS0tDQp0aXRsZTogIkV4cGxvcmF0aW9uIg0KYXV0aG9yOiAiVG9tbXkgTGFuZyINCmRhdGU6ICI3LzMvMjAxOCINCm91dHB1dDoNCiAgaHRtbF9ub3RlYm9vazoNCiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUNCiAgICBkZl9wcmludDogcGFnZWQNCiAgICBmaWdfaGVpZ2h0OiA0DQogICAgZmlnX3dpZHRoOiA3DQogICAgaGlnaGxpZ2h0OiB0YW5nbw0KICAgIG51bWJlcl9zZWN0aW9uczogeWVzDQogICAgdGhlbWU6IHJlYWRhYmxlDQogICAgdG9jOiB5ZXMNCiAgICB0b2NfZmxvYXQ6IHllcw0KLS0tDQoNCiMgUGFja2FnZXMsIERhdGEgYW5kIEN1c3RvbSBGdW5jdGlvbnMNCg0KQ3VzdG9tIEZ1bmN0aW9uczoNClRoaXMgY29kZSBjaHVuayBjb250YWlucyBjdXN0b20gZnVjbnRpb25zIHRoYXQgSSB1c2UgdG8gaGVscCBhdXRvbWF0ZSBvciBtYWtlDQp0YXNrcyBlYXNpZXIuDQpgYGB7ciBtZXNzYWdlPUZBTFNFfQ0KTG9hZFBhY2thZ2VzIDwtIGZ1bmN0aW9uKHBhY2thZ2VzKSB7DQogICMgTG9hZCBvciBpbnN0YWxsIHBhY2thZ2VzIGlmIHRoZXkgYXJlbid0IGFscmVhZHkgbG9hZGVkLg0KICAjDQogICMgQXJnczoNCiAgIyAgIHBhY2thZ2VzOiBhIHZlY3RvciBvZiBwYWNrYWdlIG5hbWVzDQogICMNCiAgZm9yIChwYWNrYWdlIGluIHBhY2thZ2VzKSB7DQogICAgaWYgKCFyZXF1aXJlKHBhY2thZ2UsIGNoYXJhY3Rlci5vbmx5PVQsIHF1aWV0bHk9VCkpIHsNCiAgICAgIGlmICghcGFja2FnZSAlaW4lIGluc3RhbGxlZC5wYWNrYWdlcygpKSBpbnN0YWxsLnBhY2thZ2VzKHBhY2thZ2UpDQogICAgICBsaWJyYXJ5KHBhY2thZ2UsIGNoYXJhY3Rlci5vbmx5PVQpDQogICAgfQ0KICB9DQp9DQoNCkNvbE5hIDwtIGZ1bmN0aW9uKGRmKSB7DQogICMgUmV0dXJuIGEgdmVjdG9yIG9mIGNvbHVtbiBuYW1lcyB0aGF0IGhhdmUgTkEgdmFsdWVzDQogICMNCiAgIyBBcmdzOg0KICAjIGRmOiBkYXRhIGZyYW1lIA0KICAjDQogICMgUmV0dXJuczoNCiAgIyAgdmVjdG9yIG9mIGNvbHVtbiBuYW1lcyB0aGF0IGhhdmUgTkFzIA0KICBkZiA8LSB0YmxfZGYoZGYpDQogIHYgPC0gYygpDQogIGogPC0gMQ0KICBmb3IoaSBpbiAxOm5jb2woZGYpKSB7DQogICAgeCA8LSBkZlsgLGldDQogICAgeFJtdk5BIDwtIHhbIWlzLm5hKHgpLF0NCiAgICBsZW54IDwtIG5yb3coeCkNCiAgICBsZW54Um12TkEgPC0gbnJvdyh4Um12TkEpDQogICAgaWYobGVueCAhPSBsZW54Um12TkEgKSB7DQogICAgICB2W2pdIDwtIGNvbG5hbWVzKGRmWyAsaV0pDQogICAgICBqIDwtIGorMQ0KICAgIH0NCiAgfQ0KICByZXR1cm4odikNCn0NCmBgYA0KDQpMb2FkIFBhY2thZ2VzOg0KUGFja2FnZXMgY29udGFpbiBmdW5jdGlvbnMgdGhhdCBvdGhlcnMgd3JpdGUgdGhhdCBoZWxwIHdpdGggZG9pbmcgc3R1ZmYNCmBgYHtyLCByZXN1bHRzPUZBTFNFfQ0KIyBJIHVzZSBteSBjdXN0b20gZnVuY3Rpb24gTG9hZFBhY2thZ2VzIHRvIGxvYWQgb3IgaW5zdGFsbCBwYWNrYWdlcw0KTG9hZFBhY2thZ2VzKGMoImRwbHlyIiwgImhhdmVuIiwgInN0cmluZ3IiLCAidGlkeXIiLCAiZ2dwbG90MiIpKQ0KYGBgDQoNCg0KUmVhZCBpbiBkYXRhDQpgYGB7ciByZXN1bHRzID0gRkFMU0V9DQpkYXRhX3BhdGggPC0gJ0U6L1RvbW15L09yaWdpbmFsX0RhdGEvRGF0YScNCiMgVGhlIGxpc3QuZmlsZXMgZnVuY3Rpb24gZ2V0cyB0aGUgZmlsZSBuYW1lcyBpbiBhIHNwZWNpZmllZCBkaXJlY3RvcnkNCiMgZmlsZV9uYW1lcyBjb250YWlucyB0aGUgZmlsZSBuYW1lcyBvZiBhbGwgdGhlIGRhdGEgc2V0cw0KZmlsZV9uYW1lcyA8LSBsaXN0LmZpbGVzKHBhdGggPSBkYXRhX3BhdGgsIHJlY3Vyc2l2ZSA9IFRSVUUpDQoNCiMgSW5pdGlhbGl6ZSBhIHZlY3RvciB0byBob2xkIGRhdGEgZnJhbWUgbmFtZXMNCmRmX25hbWVzIDwtIGMoKQ0KaSA8LSAxDQoNCiMgVGhpcyBsb29wIGdvZXMgdGhyb3VnaCB0aGUgZmlsZSBuYW1lcyBhbmQgcmVhZHMgaXQgaW50byBSDQpmb3IobmFtZSBpbiBmaWxlX25hbWVzKSB7DQogICMgY3JlYXRlIHZhcmlhYmxlIG5hbWUgZm9yIGRmDQogIGRmX25hbWUgPC0gc3RyX3JlcGxhY2VfYWxsKG5hbWUsICIgfF93aXRoX2FubjJ8LnNhczdiZGF0fC9hY3NfMTZfNXlyfF9yZWNvcmRzIiwgIiIpDQogICMgcmVhZCBpbiBkYXRhDQogIGRmIDwtIHJlYWRfc2FzKHBhc3RlMChkYXRhX3BhdGgsICIvIiwgbmFtZSkpDQogICMgYXR0YWNoIGRmIHRvIHZhcmlhYmxlIG5hbWUNCiAgYXNzaWduKGRmX25hbWUsIGRmKSANCiAgcHJpbnQocGFzdGUwKCJkb25lIHdpdGg6ICIsIGRmX25hbWUsICIgIiwgaSwiLyIsbGVuZ3RoKGZpbGVfbmFtZXMpKSkNCiAgaSA8LSBpKzENCiAgIyBhZGQgdGhlIGN1cnJlbnQgaXRlcmF0aW9uIG9mIHRoZSBkYXRhIGZyYW1lIG5hbWUgdG8gdGhlIGRmX25hbWVzIHZlY3Rvcg0KICBkZl9uYW1lcyA8LSBjKGRmX25hbWVzLCBkZl9uYW1lKQ0KfQ0KYGBgDQoNCiMgRGF0YSBEZXNjcml0cGlvbnMNCg0KREYgbmFtZXMgZm9yIHRoZSBkYXRhIHRoYXQgd2FzIHJlYWQgaW4uICANCi0gVGhlcmUgYXJlIDI3IHNldHMgb2YgZGVtb2dyYXBoaWNzIGRhdGEuIDkgc2ltbGlhciBzZXRzIGZvciBlYWNoIHN0YXRlIChNQSBOQyBPUikgIA0KLSBUaGUgZGF0YSBzZXRzIHRoYXQgc3RhcnQgd2l0aCBjb3B5IGFyZSBleGFjdCBjb3BpZXMgb2Ygb3RoZXIgZGF0YXNldHMgYW5kIGNhbiBiZSBpZ25vcmVkICANCi0gVGhlIG1lZGljYXRpb25fZGV0YWlscyBkYXRhc2V0IGhhcyBzb21lIGluZm8gYWJvdXQgdGhlIGRydWcgKGV4LiBwcmljZSwgbWFudWZhY3R1cmUgZXRjLikgIA0KLSByeF9ucXR5OiBxdWFudGl0eSBvZiBORVcgb3Bpb2QgcGlsbHMgZm9yIGVhY2ggbW9udGggYnkgemlwIGNvZGUgIA0KLSByeF9ucng6IG51bWJlciBvZiBORVcgb3Bpb2QgcHJlc2NyaXB0aW9ucyBmb3IgZWFjaCBtb250aCBieSB6aXAgY29kZSAgDQotIHJ4X3RxdHk6IHF1YW50aXR5IG9mIFRPVEFMIG9waW9kIHBpbGxzIGZvciBlYWNoIG1vbnRoIGJ5IHppcCBjb2RlICANCi0gcnhfdHJ4OiBudW1iZXIgb2YgVE9UQUwgb3Bpb2QgcHJlc2NyaXB0aW9ucyBmb3IgZWFjaCBtb250aCBieSB6aXAgY29kZSAgDQpgYGB7cn0NCmRmX25hbWVzICU+JSBhcy5kYXRhLmZyYW1lKCkNCmBgYA0KICANClRoZSBtZWRpY2F0aW9uX2RldGFpbHMgZGF0YXNldCBoYXMgc29tZSBpbmZvIGFib3V0IHRoZSBkcnVnIChleC4gcHJpY2UsIG1hbnVmYWN0dXJlIGV0Yy4pDQpgYGB7cn0NCm1lZGljYXRpb25fZGV0YWlscw0KYGBgDQogIA0KcnhfbnF0eTogcXVhbnRpdHkgb2YgTkVXIG9waW9kIHBpbGxzIGZvciBlYWNoIG1vbnRoIGJ5IHppcCBjb2RlDQpgYGB7cn0NCnJ4X25xdHkNCmBgYA0KICANCnJ4X25yeDogbnVtYmVyIG9mIE5FVyBvcGlvZCBwcmVzY3JpcHRpb25zIGZvciBlYWNoIG1vbnRoIGJ5IHppcCBjb2RlDQpgYGB7cn0NCnJ4X25yeA0KYGBgDQogIA0KcnhfdHF0eTogcXVhbnRpdHkgb2YgVE9UQUwgb3Bpb2QgcGlsbHMgZm9yIGVhY2ggbW9udGggYnkgemlwIGNvZGUNCmBgYHtyfQ0KcnhfdHF0eQ0KYGBgDQogIA0KcnhfdHJ4OiBudW1iZXIgb2YgVE9UQUwgb3Bpb2QgcHJlc2NyaXB0aW9ucyBmb3IgZWFjaCBtb250aCBieSB6aXAgY29kZQ0KYGBge3J9DQpyeF90cngNCmBgYA0KICANCk1BX3MwMTAxOiBBZ2UgYW5kIHNleCBkZW1vZ3JhcGhpY3MgZGF0YSBmb3IgZWFjaCB6aXAgY29kZSBpbiBtYXNzYWNodXNldHRzICANCkNvbHVtbiBIQzAxX0VTVF9WQzAxOiBpcyB0b3RhbCBwb3B1bGF0aW9uIGZvciB0aGUgcmVzcGVjdGl2ZSB6aXAgY29kZSAgDQpDb2x1bW4gSEMwMl9FU1RfVkMwMTogdG90YWwgbWFsZSBwb3B1bGF0aW9uIGZvciB0aGUgcmVzcGVjdGl2ZSB6aXAgY29kZSAgDQpDb2x1bW4gSEMwM19FU1RfVkMwMTogdG90YWwgZmVtYWwgcG9wdWxhdGlvbiBmb3IgcmVzcGVjdGl2ZSB6aXAgY29kZSAgDQotIFlvdSBjYW4gdmlldyB0aGUgZGF0YSBkaWN0aW9uYXJ5IHRvIGZpbmQgb3V0IHdoYXQgdGhlIG90aGVyIGNvbHVtbnMgbWVhbiAgDQotIFRoZSBvdGhlciBkZW1vZ3JhcGhpY3MgZGF0YSBzZXRzIGxpa2VseSBoYXZlIGEgdmVyeSBzaW1pYWxyIGZvcm1hdCAgDQpgYGB7cn0NCk1BX3MwMTAxDQpgYGANCg0KICANCkNoZWNrIHRoYXQgdGhlIGZpbGVzIG5hbWVkIHdpdGggY29weSByZWFsbHkganVzdCBhcmUgZHVwbGljYXRlcyAgDQpgYGB7ciwgcmVzdWx0cz1GQUxTRX0NCnJ4X25xdHkgJT4lDQogIGFsbF9lcXVhbChDb3B5b2ZyeF9ucXR5KQ0KQ29weW9mcnhfbnJ4ICU+JQ0KICBhbGxfZXF1YWwocnhfbnJ4KQ0KQ29weW9mcnhfdHF0eSAlPiUNCiAgYWxsX2VxdWFsKENvcHlvZnJ4X3RxdHkpDQpDb3B5b2ZyeF90cnggJT4lDQogIGFsbF9lcXVhbChyeF90cngpDQpgYGANCg0KIyBUb3RhbCBSeCBCeSBTdGF0ZQ0KDQpQcmVwYXJlIGRhdGEgdG8gc2VlIHRvdGFsIHJ4IGJ5IHN0YXRlIGZvciBlYWNoIG1vbnRoDQpgYGB7cn0NCnJ4X3RyeF90IDwtIHJ4X3RyeCAlPiUgc2VsZWN0KFNULCBzdGFydHNfd2l0aCgiVFJ4IikpDQoNCnJ4X3RyeF90IDwtIHJ4X3RyeCAlPiUNCiAgc2VsZWN0KFNULCBzdGFydHNfd2l0aCgiVFJ4IikpICU+JQ0KICBncm91cF9ieShTVCkgJT4lIA0KICBzdW1tYXJpc2VfYWxsKGZ1bnMoc3VtKC4pKSkgJT4lIA0KICB1bmdyb3VwKCkgJT4lIA0KICBnYXRoZXIoa2V5ID0gImRhdGUiLCB2YWx1ZSA9IFRSeCwgLVNUKSAlPiUNCiAgbXV0YXRlKGRhdGUgPSBzdHJfcmVwbGFjZV9hbGwoZGF0ZSwgIlRSeF8iLCAiIikpICU+JSANCiAgbXV0YXRlKGRhdGUgPSBhcy5EYXRlKGRhdGUsICclbSVkJVknKSkgJT4lDQogIG11dGF0ZShwb3AgPSBpZmVsc2UoU1QgPT0gJ01BJywgNi44NiwgDQogICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKFNUID09ICJPUiIsIDQuMTQzLCAxMC4yNykpLA0KICAgICAgICAgcnhfcG9wX3JhdGlvID0gVFJ4IC8gcG9wKQ0KDQojIHByZXBhcmUgZGF0YSB0byBzZWUgZGlmZmVyZW5jZSBiZXR3ZWVuIHRvdGFsIHJ4IGZvciBOQyBhbmQgTUENCk1BX3J4X3BvcCA8LSByeF90cnhfdCAlPiUgDQogIGZpbHRlcihTVCA9PSAiTUEiKSAlPiUgDQogIG11dGF0ZShNQV9yeCA9IHJ4X3BvcF9yYXRpbykgJT4lIA0KICBzZWxlY3QoTUFfcngpDQoNCk9SX3J4X3BvcCA8LSByeF90cnhfdCAlPiUgDQogIGZpbHRlcihTVCA9PSAiT1IiKSAlPiUgDQogIG11dGF0ZShPUl9yeCA9IHJ4X3BvcF9yYXRpbykgJT4lIA0KICBzZWxlY3QoT1JfcngpDQoNCk5DX3J4X3BvcCA8LSByeF90cnhfdCAlPiUgDQogIGZpbHRlcihTVCA9PSAiTkMiKSAlPiUgDQogIG11dGF0ZShOQ19yeCA9IHJ4X3BvcF9yYXRpbykgJT4lIA0KICBzZWxlY3QoTkNfcngpDQoNCmRpZmZfZGYgPC0gYmluZF9jb2xzKHJ4X3RyeF90ICU+JSBkaXN0aW5jdChkYXRlKSwgTUFfcnhfcG9wLCBPUl9yeF9wb3AsIE5DX3J4X3BvcCkgJT4lDQogIG11dGF0ZShOQ19NQV9kaWZmID0gTkNfcnggLSBNQV9yeCkNCg0KYGBgDQoNCkxpbmUgcGxvdCBvZiB0b3RhbCByeCBieSBzdGF0ZSBmb3IgZWFjaCBtb250aA0KYGBge3J9DQpnZ3Bsb3QoZGF0YSA9IHJ4X3RyeF90LCBhZXMoeCA9IGRhdGUsIHkgPSBUUngsIGNvbG9yID0gU1QpKSArDQogIGdlb21fbGluZSgpICsNCiAgZ2d0aXRsZSgiVG90YWwgUngiKQ0KDQpnZ3Bsb3QoZGF0YSA9IHJ4X3RyeF90LCBhZXMoeCA9IGRhdGUsIHkgPSByeF9wb3BfcmF0aW8sIGNvbG9yID0gU1QpKSArDQogIGdlb21fbGluZSgpICsNCiAgZ2d0aXRsZSgiVG90YWwgUnggcGVyIE1pbGxpb24gUmVzaWRlbnRzIikNCg0KZ2dwbG90KGRhdGEgPSBkaWZmX2RmLCBhZXMoeCA9IGRhdGUsIHkgPSBOQ19NQV9kaWZmKSkgKw0KICBnZW9tX2xpbmUoKSArDQogIGdndGl0bGUoIkRpZmYgVG90YWwgUnggcGVyIE1pbGxpb24gUmVzaWRlbnRzIEJldHdlZW4gTkMgYW5kIE1BIikNCmBgYA0KICANCiAgDQpCYXIgQ2hhcnQgb2YgVG90YWwgU2NyaXB0cyBmb3IgZWFjaCBTdGF0ZQ0KYGBge3J9DQoNCmdncGxvdChkYXRhID0gcnhfdHJ4X3QgJT4lIGZpbHRlcihkYXRlID09ICcyMDE3LTA4LTMxJyksIGFlcyh4ID0gU1QsIHkgPSByeF9wb3BfcmF0aW8pKSArDQogIGdlb21fY29sKCkgKw0KICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpjb21tYSkgKw0KICBnZ3RpdGxlKCJUb3RhbCBTY3JpcHRzIFBlciBNaWwgUmVzaWRlbnRzIGluIEF1Z3VzdCIpDQpgYGANCg0KDQojIE1JU0MgKHNjcmF0Y2ggLyBqdW5rKS4NCg0KDQpgYGB7cn0NCmZvbyA8LSByeF90cnggJT4lIGdyb3VwX2J5KGNpdHksIFNULCBaaXApICU+JSBzdW1tYXJpc2Uoc3VtKFRSeF8wODMxMjAxNykpDQpgYGANCg0KYGBge3J9DQojIGNhc3QgdG8gbnVtZXJpYyBkYXRhIHR5cGUNCk1BX3MwMTAxX2QgPC0gTUFfczAxMDEgJT4lIG11dGF0ZV9hbGwoZnVucyhhcy5kb3VibGUoLikpKQ0KDQojIGdldCBjb2wgbmFtZXMgdGhhdCBoYXZlIE5BIHZhbHVlcw0KbmEgPC0gQ29sTmEoTUFfczAxMDFfZCkNCg0KIyBnZXQgYWxsIGNvbCBuYW1lcw0KYWxsIDwtIG5hbWVzKE1BX3MwMTAxKQ0KDQojIHRoaXMgIGlzIGNvbHVtbiBuYW1lcyB0aGF0IGRvbid0IGhhdmUgYW55IE5BIHZhbHVlcw0Kc2V0ZGlmZihhbGwsbmEpDQpgYGANCg0KDQpXcml0ZSBkYXRlc2V0cyBvdXQgYXMgY3N2IGZpbGVzDQpgYGB7cn0NCmZvciAobmFtZSBpbiBkZl9uYW1lcykgew0KICB3cml0ZS5jc3YoZ2V0KG5hbWUpLCBwYXN0ZTAoJ0U6L1RvbW15L3NjcmF0Y2gvY3N2LycsbmFtZSwiLmNzdiIpKQ0KfQ0KDQpgYGANCg0K